﻿/*
 * KLF Headless Browser
 * Written by Kris Oye <kristianoye@gmail.com>
 * Copyright (C) 2011-2012.  All rights reserved.
 */
namespace KLF.Lib.Browser
{
    #region Using Statements

    using System;
    using KLF.Lib.Browser.DOM.HTML;
    using KLF.Lib.Browser.DOM.CSS.SAC;
    using KLF.Lib.Browser.DOM.CSS.SAC.Selectors;
    using KLF.Lib.Browser.DOM.CSS.SAC.Conditions;
    using Antlr.Runtime;

    #endregion

    public enum AttOp
    {
        HasAttribute,
        Equals,
        ContainsS,
        ContainsH,
        StartsWith,
        EndsWith,
        Contains
    }

    /// <summary>
    /// An idea similar to Watin.  This class begins construction of a possible
    /// chain of selector criteria.
    /// 
    /// e.g.
    /// Find.ByElementName("input").ById("searchbox")
    /// 
    /// The result of which can be used in various browser functions.
    /// 
    /// Example:
    /// browser.SetValue(Find.ById("mySearchBox", "jQuery 1.4.2"));
    /// browser.Click(Find.ByCriteria("mySearchBox > mySearchSubmit"));
    /// </summary>
    public sealed class Find
    {
        /// <summary>
        /// Finds a 
        /// </summary>
        /// <param name="attName"></param>
        /// <param name="attOp"></param>
        /// <param name="attVal"></param>
        /// <returns></returns>
        public static Selector ByAttribute(string attName, AttOp attOp, string attVal)
        {
            return new ElementSelector()
                .ByAttribute(attName, attOp, attVal);
        }

        /// <summary>
        /// Find an element by it's class attribute.  Multiple classes may be
        /// specified if delimited with spaces.
        /// </summary>
        /// <param name="criteria"></param>
        /// <returns></returns>
        public static Selector ByClass(string criteria)
        {
            return new ElementSelector()
                .ByClass(criteria);
        }

        /// <summary>
        /// Find a link or something by a HREF.
        /// </summary>
        /// <param name="criteria"></param>
        /// <returns></returns>
        public static Selector ByHref(string criteria)
        {
            return new ElementSelector()
                .ByAttribute(HTMLConstants.HTML_ATT_HREF, AttOp.Equals, criteria);
        }

        /// <summary>
        /// Find an element by it's id attribute.
        /// </summary>
        /// <param name="criteria"></param>
        /// <returns></returns>
        public static Selector ById(string criteria)
        {
            return new ElementSelector()
                .ById(criteria);
        }

        /// <summary>
        /// Find an element by it's name attribute.
        /// </summary>
        /// <param name="criteria"></param>
        /// <returns></returns>
        public static Selector ByName(string criteria)
        {
            return new ElementSelector()
                .ByAttribute(HTMLConstants.HTML_ATT_NAME, AttOp.Equals, criteria);
        }

        /// <summary>
        /// A heavier approach.
        /// </summary>
        /// <param name="criteria"></param>
        /// <returns></returns>
        public static Selector BySelector(string criteria)
        {
            CSS21Lexer lexer = new CSS21Lexer(new ANTLRStringStream(criteria));
            CSS21Parser parser = new CSS21Parser(new CommonTokenStream(lexer));
            
            return parser.getSelectorList();
        }

        /// <summary>
        /// Find an element by it's element tag name.
        /// </summary>
        /// <param name="criteria"></param>
        /// <returns></returns>
        public static Selector ByTag(string criteria)
        {
            return new ElementSelector() { ElementName = criteria };
        }
    }
}
